﻿namespace Bildverarbeitung.CGFilter
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Drawing.Imaging;
    using System.IO;
    using AForge.Imaging;
    using AForge;
    using AForge.Math.Geometry;
    using AForge.Imaging.Filters;
    using Bildverarbeitung;

    /// <summary>
    /// 
    /// </summary>
    public class HeinzPatrikFilter : Bildverarbeitung.IFilter
    {
        /// <summary>
        /// Gets the summerized difference from average of all images.
        /// </summary>
        /// <param name="images">Given images.</param>
        /// <returns>The summerized difference.</returns>
        public Bitmap GetImageWithDoor(Bitmap srcImg)
        {
            if (srcImg != null)
            {
                Bitmap image = AForge.Imaging.Filters.Grayscale.CommonAlgorithms.BT709.Apply(srcImg);
                // create filter
                AForge.Imaging.Filters.SobelEdgeDetector edgeFilter = new AForge.Imaging.Filters.SobelEdgeDetector();
                //AForge.Imaging.Filters.HomogenityEdgeDetector edgeFilter = new AForge.Imaging.Filters.HomogenityEdgeDetector();
                //AForge.Imaging.Filters.DifferenceEdgeDetector edgeFilter = new AForge.Imaging.Filters.DifferenceEdgeDetector();
                //AForge.Imaging.Filters.CannyEdgeDetector edgeFilter = new AForge.Imaging.Filters.CannyEdgeDetector();
                edgeFilter.ApplyInPlace(image);

                image = image.Clone(new Rectangle(0, 0, image.Width, image.Height), PixelFormat.Format24bppRgb);

                //detect rectangles
                List<List<IntPoint>> rectangles = shapeChecker(image);

                //paint in the source image!!!!!!!!!!!!! not the edge image!!!!!!!!!!!!!!!!!!
                image = srcImg;

                //set the color saturation to 20%
                SaturationCorrection saturationFilter = new SaturationCorrection(-0.8f);
                saturationFilter.ApplyInPlace(image);

                //draw rectangle cornerPoints, borders and calc the biggest rectangle
                List<IntPoint> biggestRectangleCorners = null;
                float biggestRectangleArea = 0;
                Graphics g = Graphics.FromImage(image);
                Pen redPen = new Pen(Color.Red, 4);
                Pen greenPen = new Pen(Color.Green, 4);

                foreach (List<IntPoint> corners in rectangles)
                {
                    if (corners.Count == 4)
                    {
                        //save the biggest rectangle
                        if (calcPolygonArea(corners) > biggestRectangleArea)
                        {
                            biggestRectangleArea = calcPolygonArea(corners);
                            biggestRectangleCorners = corners;
                        }
                        //draw cornerPoints
                        foreach (IntPoint point in corners)
                        {
                            //log(point.X + "-" + point.Y);
                            g.DrawRectangle(redPen, point.X - 2, point.Y - 2, 5, 5);
                        }
                        //draw rectangle borders
                        g.DrawPolygon(greenPen, ToPointsArray(corners));
                    }
                }

                //color the biggest rectangle
                if (biggestRectangleCorners != null)
                {
                    SolidBrush yellowBrush = new SolidBrush(Color.Yellow);
                    g.FillPolygon(yellowBrush, ToPointsArray(biggestRectangleCorners));
                    yellowBrush.Dispose();
                }

                greenPen.Dispose();
                redPen.Dispose();
                g.Dispose();
                
                //image.Save("..\\..\\..\\test.png");
                return image;
            }
            return null;
        }

        //calculate the area of the polygon
        //http://de.wikipedia.org/wiki/Polygon#Fl.C3.A4che
        private float calcPolygonArea(List<IntPoint> corners)
        {
            float area = 0;
            int iPlusOne;

            for (int i = 0; i < corners.Count; i++)
            {
                iPlusOne = (i + 1) % (corners.Count);
                area += (corners[i].Y + corners[iPlusOne].Y) * (corners[i].X - corners[iPlusOne].X);
            }
            return area / 2;
        }


        // Process image
        // source: Simple Shape Checker sample application - AForge.NET framework
        private List<List<IntPoint>> shapeChecker(Bitmap bitmap)
        {
            List<List<IntPoint>> rectangleCorners = new List<List<IntPoint>>();
            // lock image
            BitmapData bitmapData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.ReadWrite, bitmap.PixelFormat);

            // step 1 - turn background to black
            ColorFiltering colorFilter = new ColorFiltering();

            colorFilter.Red = new IntRange(0, 64);
            colorFilter.Green = new IntRange(0, 64);
            colorFilter.Blue = new IntRange(0, 64);
            colorFilter.FillOutsideRange = false;

            colorFilter.ApplyInPlace(bitmapData);

            // step 2 - locating objects
            BlobCounter blobCounter = new BlobCounter();

            blobCounter.FilterBlobs = true;
            blobCounter.MinHeight = 5;
            blobCounter.MinWidth = 5;

            blobCounter.ProcessImage(bitmapData);
            Blob[] blobs = blobCounter.GetObjectsInformation();
            bitmap.UnlockBits(bitmapData);

            // step 3 - check objects' type and highlight
            SimpleShapeChecker shapeChecker = new SimpleShapeChecker();

            //Graphics g = Graphics.FromImage(bitmap);
            //Pen yellowPen = new Pen(Color.Yellow, 2); // circles
            //Pen redPen = new Pen(Color.Red, 2);       // quadrilateral
            //Pen brownPen = new Pen(Color.Brown, 2);   // quadrilateral with known sub-type
            //Pen greenPen = new Pen(Color.Green, 2);   // known triangle
            //Pen bluePen = new Pen(Color.Blue, 2);     // triangle

            for (int i = 0, n = blobs.Length; i < n; i++)
            {
                List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);

                List<IntPoint> corners;

                // is triangle or quadrilateral
                if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
                {
                    // get sub-type
                    PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);

                    //Pen pen;

                    if (subType == PolygonSubType.Unknown)
                    {
                        //pen = (corners.Count == 4) ? redPen : bluePen;
                        //rectangleCorners.Add(corners);
                    }
                    else
                    {
                        rectangleCorners.Add(corners);
                        //pen = (corners.Count == 4) ? brownPen : greenPen;
                    }

                    //g.DrawPolygon(pen, ToPointsArray(corners));
                }
                //}
            }

            //yellowPen.Dispose();
            //redPen.Dispose();
            //greenPen.Dispose();
            //bluePen.Dispose();
            //brownPen.Dispose();
            //g.Dispose();

            // put new image to clipboard
            //Clipboard.SetDataObject(bitmap);
            // and to picture box
            //pictureBox.Image = bitmap;
            //UpdatePictureBoxPosition();
            return rectangleCorners;
        }

        private System.Drawing.Point[] ToPointsArray(List<IntPoint> points)
        {
            System.Drawing.Point[] array = new System.Drawing.Point[points.Count];

            for (int i = 0, n = points.Count; i < n; i++)
            {
                array[i] = new System.Drawing.Point(points[i].X, points[i].Y);
            }

            return array;
        }

        /// <summary>
        /// Return the author´s name
        /// Please use NachnameVorname (without spaces).
        /// </summary>
        /// <returns>author´s name</returns>
        public String GetName()
        {
            return ("HeinzPatrik");
        }
    }
}
